package com.batchengine.db;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.sql.*;

/**
 * Created by sunil.incubator@yahoo.com.
 * User: sunil.kalva
 * Date: Mar 11, 2009
 */
public class DBProxyFactory {

    /**
     * Class[] for CallableStatement interface.
     */
    private static final Class[] callableStatementClass = new Class[]{CallableStatement.class};

    /**
     * Class[] for Connection interface.
     */
    private static final Class[] connectionClass = new Class[]{Connection.class};

    /**
     * Class[] for Driver interface.
     */
    private static final Class[] driverClass = new Class[]{Driver.class};

    /**
     * The Singleton instance of this class.
     */
    private static final DBProxyFactory instance = new DBProxyFactory();

    /**
     * Class[] for ResultSetMetaData interface.
     */
    private static final Class[] metaClass = new Class[]{ResultSetMetaData.class};

    /**
     * Class[] for PreparedStatement interface.
     */
    private static final Class[] preparedStatementClass = new Class[]{PreparedStatement.class};

    /**
     * Class[] for ResultSet interface.
     */
    private static final Class[] resultSetClass = new Class[]{ResultSet.class};

    /**
     * Class[] for Statement interface.
     */
    private static final Class[] statementClass = new Class[]{Statement.class};

    /**
     * Returns the Singleton instance of this class.
     *
     * @return singleton instance
     */
    public static DBProxyFactory instance() {
        return instance;
    }

    /**
     * Protected constructor for DBProxyFactory subclasses to use.
     */
    protected DBProxyFactory() {
        super();
    }

    /**
     * Creates a new proxy <code>CallableStatement</code> object.
     *
     * @param handler The handler that intercepts/overrides method calls.
     * @return proxied CallableStatement
     */
    public CallableStatement createCallableStatement(InvocationHandler handler) {

        return (CallableStatement) Proxy.newProxyInstance(handler.getClass().getClassLoader(), callableStatementClass, handler);
    }

    /**
     * Creates a new proxy <code>Connection</code> object.
     *
     * @param handler The handler that intercepts/overrides method calls.
     * @return proxied Connection
     */
    public Connection createConnection(InvocationHandler handler) {

        return (Connection) Proxy.newProxyInstance(handler.getClass().getClassLoader(), connectionClass, handler);
    }

    /**
     * Creates a new proxy <code>Driver</code> object.
     *
     * @param handler The handler that intercepts/overrides method calls.
     * @return proxied Driver
     */
    public Driver createDriver(InvocationHandler handler) {

        return (Driver) Proxy.newProxyInstance(handler.getClass().getClassLoader(), driverClass, handler);
    }

    /**
     * Creates a new proxy <code>PreparedStatement</code> object.
     *
     * @param handler The handler that intercepts/overrides method calls.
     * @return proxied PreparedStatement
     */
    public PreparedStatement createPreparedStatement(InvocationHandler handler) {

        return (PreparedStatement) Proxy.newProxyInstance(handler.getClass().getClassLoader(), preparedStatementClass, handler);
    }

    /**
     * Creates a new proxy <code>ResultSet</code> object.
     *
     * @param handler The handler that intercepts/overrides method calls.
     * @return proxied ResultSet
     */
    public ResultSet createResultSet(InvocationHandler handler) {

        return (ResultSet) Proxy.newProxyInstance(handler.getClass().getClassLoader(), resultSetClass, handler);
    }

    /**
     * Creates a new proxy <code>ResultSetMetaData</code> object.
     *
     * @param handler The handler that intercepts/overrides method calls.
     * @return proxied ResultSetMetaData
     */
    public ResultSetMetaData createResultSetMetaData(InvocationHandler handler) {

        return (ResultSetMetaData) Proxy.newProxyInstance(handler.getClass().getClassLoader(), metaClass, handler);
    }

    /**
     * Creates a new proxy <code>Statement</code> object.
     *
     * @param handler The handler that intercepts/overrides method calls.
     * @return proxied Statement
     */
    public Statement createStatement(InvocationHandler handler) {

        return (Statement) Proxy.newProxyInstance(handler.getClass().getClassLoader(), statementClass, handler);
    }
}
